home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / More Source / C⁄C++ / offscreen2 / offscreen2.c next >
C/C++ Source or Header  |  1994-05-04  |  15KB  |  590 lines

  1. /*
  2. *    FILE:        offscreen2.c
  3. *    AUTHOR:        R. Gonzalez
  4. *    CREATED:    June 28, 1993
  5. *
  6. *    Demonstrates
  7. *    offscreen drawing. Code taken from CopyBits example in Think Ref 2.0
  8. *    and from Offscreen Graphics example. (Also tried Offscreen PixMaps
  9. *    example and Creating Offscreen BitMaps example.)
  10. *
  11. *    This version checks for presence of Color QuickDraw.
  12. *
  13. *    It also tries to sync to vertical retrace -- doesn't work if bitmap too large.
  14. *
  15. *    Try using global coords for NewGWorld rec.
  16. *
  17. *    PROJECT CONTENTS:
  18. *        offscreen.c, MacTraps, ANSI
  19. *
  20. *    COMPILATION:
  21. *        68881 code generation if avail. MacHeaders prefix.
  22. */
  23.  
  24. # define CENTER_X    0.
  25. # define CENTER_Y    0.
  26. # define SPOKE_SIZE    .6
  27. # define RADIUS1    .5
  28. # define RADIUS2    .4
  29. # define RADIUS3    .3
  30. # define PI            3.1415926
  31. # define INCR        PI/30.
  32. # define MAP_WIDE 300
  33. # define MAP_HIGH 300
  34.  
  35. # define OFFSCREEN    // comment this out to see effect
  36.  
  37. //    For B&W case:
  38. #define MAP_WBYTES  ( ( ( MAP_WIDE / 16 ) +1 ) * 2 )
  39. #define MAP_SIZE ( MAP_WBYTES * MAP_HIGH )
  40. //
  41.  
  42. //    For Color case:
  43. # include    <QDOffscreen.h>
  44. //
  45.  
  46. # include    <math.h>
  47. # include    <GestaltEqu.h>
  48.  
  49. void    init_graphics(void);
  50. double    get_aspect_ratio(void);
  51. void    set_view(double,double,double,double);
  52. void    draw_line(double,double,double,double);    
  53. void    move_to(double,double);
  54. void    draw_to(double,double);
  55. void    draw_circle(double,double,double);    
  56. void    fill_circle(double,double,double);    
  57. int        mouse_button_is_down(void);
  58. void    get_mouse_location(double*,double*);
  59. void    wait(void);        
  60.  
  61. WindowPtr    myWindow;
  62. Boolean        color_QD,        // used to initialize window and offscreen bit/pixmap
  63.             color_avail;    // use this to decide what maps to black and white
  64.  
  65. # define    SMALL_COPY_RECT    // use to find smallest rect which needs to be redrawn
  66. Rect        circle_rect;    
  67.  
  68. # define    SYNC    // For syncing to vertical retrace. (From Alex Chafee in c.s.m.p.)
  69.  
  70. # ifdef SYNC
  71. # include    <Retrace.h>
  72. # include    <Start.h>
  73.  
  74. typedef struct
  75. {
  76.     long    goodA5;
  77.     VBLTask    task;
  78. } MYVBLTASK;
  79.  
  80. void    InstallSync(void);
  81. void    WaitForSync(void);
  82. void    RemoveSync(void);
  83. pascal void Task(void);
  84.  
  85. long        vCounter;    // like Ticks
  86. long        vblJunk;
  87. MYVBLTASK    mytask;
  88. DefVideoRec    video;
  89. # endif
  90.  
  91. # define GLOBAL    // not sure this is necessary...
  92.  
  93. main()
  94. {
  95.     double    x,
  96.             y,
  97.             old_x,
  98.             old_y,
  99.             angle = 0.;
  100.     Rect sRect,dRect;
  101.     Rect changed_rect,        // CopyBits on the entire window is too slow for proper
  102.          rect2;                // syncing, so we'll make a rect which holds the new
  103.                              // and old images.
  104. # ifdef GLOBAL
  105.     Rect    r,
  106.             *pr;
  107. # endif
  108.  
  109. //    For B&W case:
  110.     BitMap saveMap,tempMap;
  111. //
  112. //    For Color case:
  113.     GWorldPtr currPort;    // Saves the current port prior to setting up
  114.                             // offscreen world
  115.     GDHandle currDev;       // Saves the current device prior to setting up
  116.                             // offscreen world
  117.     GWorldPtr gMyOffG;    // Pointer to OffScreen Graphics World
  118. //
  119.  
  120.     init_graphics();    /* Don't forget to do this FIRST! */
  121.     
  122. # ifdef SYNC
  123.     InstallSync();
  124. # endif
  125.     
  126. # ifdef OFFSCREEN
  127.     if (!color_QD)
  128.     {
  129.         // allocate new B&W "canvas"
  130.         tempMap.baseAddr = ( QDPtr )NewPtr( MAP_SIZE  );
  131.         tempMap.rowBytes = MAP_WBYTES;    // initialize needed fields
  132.         tempMap.bounds = myWindow->portRect;
  133.         saveMap =  myWindow->portBits;
  134. # ifndef SMALL_COPY_RECT
  135.         sRect = dRect = myWindow->portRect;    // set source and destination rects
  136. # endif
  137.         SetPortBits( &tempMap );
  138.     }
  139.     else
  140.     {
  141.         // Build Offscreen Graphics world
  142.         GetGWorld(&currPort,&currDev);
  143.  
  144.         // Create Offscreen Graphics world.
  145. # ifdef GLOBAL
  146.         r = myWindow->portRect;
  147.         LocalToGlobal((Point*) &r);
  148.         LocalToGlobal(((Point*) &r) +1);
  149.         NewGWorld(&gMyOffG, 0, &r, nil, nil, 0);
  150.         pr = &gMyOffG->portRect;
  151.         OffsetRect(pr,-pr->left,-pr->top);
  152. # else
  153.         NewGWorld(&gMyOffG, 0, &myWindow->portRect, nil, nil, 0);
  154. # endif
  155.  
  156.         // Lock down Pixels that we are drawing to so that memory will not move
  157.         LockPixels (gMyOffG->portPixMap);
  158.         // Setup drawing area to be our offscreen graphics world
  159. # ifndef SMALL_COPY_RECT
  160.         sRect = dRect = myWindow->portRect;    // set source and destination rects
  161. # endif
  162.         SetGWorld (gMyOffG, nil);
  163.     }
  164.  
  165.     BackColor(whiteColor);    // for proper operation of CopyBits()
  166.     
  167.     EraseRect( &myWindow->portRect );    
  168. // with color QD can also say: EraseRect(&(*gMyOffG->portPixMap)->bounds);
  169.  
  170. # endif
  171.  
  172.     old_x = RADIUS1 + CENTER_X;
  173.     old_y = CENTER_Y;
  174.     
  175.     while (!mouse_button_is_down())
  176.     {
  177. # ifdef OFFSCREEN
  178.         if (!color_QD)    
  179.             SetPortBits( &tempMap );
  180.         else
  181.             SetGWorld (gMyOffG, nil);
  182. # endif
  183.  
  184.         x = cos(angle)*SPOKE_SIZE + CENTER_X;
  185.         y = sin(angle)*SPOKE_SIZE + CENTER_Y;
  186.  
  187. //        erase last drawing:
  188.         ForeColor(whiteColor);
  189.         fill_circle(old_x,old_y,RADIUS1);
  190.         rect2 = circle_rect;
  191. //
  192.         
  193.         ForeColor(cyanColor);    // non-white colors map to black for B&W case.
  194.                                 // In that case I won't fill this circle
  195.         if (color_avail)
  196.             fill_circle(x,y,RADIUS1);
  197.         else
  198.             draw_circle(x,y,RADIUS1);
  199.         
  200.         UnionRect(&circle_rect,&rect2,&changed_rect);
  201. # ifdef SMALL_COPY_RECT
  202.         sRect = dRect = changed_rect;
  203. # endif
  204.  
  205.         ForeColor(yellowColor);
  206.         
  207.         if (color_avail)
  208.             fill_circle(x,y,RADIUS2);
  209.         else
  210.             draw_circle(x,y,RADIUS2);
  211.  
  212.         ForeColor(magentaColor);
  213.         fill_circle(x,y,RADIUS3);
  214.         
  215.         old_x = x;
  216.         old_y = y;
  217.         angle += INCR;
  218.  
  219. # ifdef OFFSCREEN
  220.         if (!color_QD)    
  221.         {
  222.             SetPortBits( &saveMap );
  223.             ForeColor(blackColor);        // entire bitmap is drawn in this color
  224. # ifdef SYNC
  225.             WaitForSync();
  226. # endif
  227.             CopyBits(&tempMap,&myWindow->portBits, &sRect, &dRect, srcCopy, nil);
  228.         }
  229.         else
  230.         {
  231.             SetGWorld (currPort, currDev);
  232.             ForeColor(blackColor);        // to preserve proper colors
  233. # ifdef SYNC
  234.             WaitForSync();
  235. # endif
  236.             CopyBits((BitMap *) (*(gMyOffG->portPixMap)),
  237.                 &((GrafPtr)myWindow)->portBits, &sRect, &dRect, srcCopy, nil);
  238.         }
  239. # endif
  240.     }
  241.     
  242. # ifdef OFFSCREEN
  243.     if (!color_QD)    
  244.         DisposePtr((Ptr)tempMap.baseAddr);    // free up canvas RAM
  245.     else
  246.     {
  247.         // Now unlock Pixels.
  248.         UnlockPixels (gMyOffG->portPixMap);
  249.         DisposeGWorld(gMyOffG);
  250.     }
  251. # endif
  252.  
  253. # ifdef SYNC
  254.     RemoveSync();
  255. # endif
  256. }
  257.  
  258. /////////////////////////////////////////////////////////////////////////
  259. //    Following code adapted from macgraph-ANSI.c
  260. /////////////////////////////////////////////////////////////////////////
  261.  
  262. # define    NIL_POINTER            0L
  263. # define    MOVE_TO_FRONT        -1L
  264. # define    REMOVE_ALL_EVENTS    0
  265. # define    TITLE                "\pGraphics"
  266. # define    VISIBLE                1
  267. # define    NO_GO_AWAY            0
  268. # define    NIL_REF_CON            NIL_POINTER
  269. # define    BACKGROUND            BLACK
  270.  
  271. static WindowPtr    gDrawWindow,
  272.                     gConsoleWindow;
  273. static CursHandle    gCursor;
  274. static int            gDrawwidth,
  275.                     gDrawheight,
  276.                     gPresentcolor;
  277. static double        gViewwidth = 2.,
  278.                     gViewheight = 2.,
  279.                     gViewx = 1.,
  280.                     gViewy = 1.;
  281.  
  282. static int            transform_x(double),
  283.                     transform_y(double);
  284.                     
  285. /************************************************************************
  286. *    You must call init_graphics() at the beginning of main().
  287. *    Likely don't need all these initializations; they are taken from Mark
  288. *    & Reed's "Macintosh Programming Primer", Addison-Wesley, 1989
  289. ************************************************************************/
  290. void    init_graphics(void)
  291. {
  292.     double    aspect;
  293.     Rect    rectangle;
  294.     short int    left,
  295.                 right,
  296.                 top,
  297.                 bottom;
  298.     long        temp;
  299.     
  300.     left = 5;
  301.     right = MAP_WIDE+left;
  302.     top = 45;
  303.     bottom = MAP_HIGH+top;
  304.         
  305.     SetRect(&rectangle,left,top,right,bottom);
  306.     
  307.     InitGraf(&thePort);
  308.     InitFonts();
  309.     FlushEvents(everyEvent,REMOVE_ALL_EVENTS);    
  310.     InitWindows();
  311.     InitMenus();
  312.     TEInit();
  313.     InitDialogs(NIL_POINTER);
  314.     InitCursor();
  315.  
  316. //    Check for color availability:
  317.     Gestalt(gestaltQuickdrawVersion,&temp);
  318.     color_QD = temp >= gestalt8BitQD;
  319. //
  320.  
  321.     if (!color_QD)
  322.     {
  323.         gDrawWindow = NewWindow(NIL_POINTER,&rectangle,
  324.             TITLE,VISIBLE,plainDBox,(WindowPtr) MOVE_TO_FRONT,NO_GO_AWAY,NIL_REF_CON);
  325.         color_avail = false;
  326.     }
  327.     else
  328.     {
  329.         gDrawWindow = NewCWindow(NIL_POINTER,&rectangle,
  330.             TITLE,VISIBLE,plainDBox,(CWindowPtr) MOVE_TO_FRONT,NO_GO_AWAY,NIL_REF_CON);
  331.         color_avail = (**((CGrafPtr) gDrawWindow)->portPixMap).pixelSize > 1;
  332.     }
  333.  
  334.     SetPort(gDrawWindow);
  335.     gDrawwidth = gDrawWindow->portRect.right - gDrawWindow->portRect.left;
  336.     gDrawheight = gDrawWindow->portRect.bottom - gDrawWindow->portRect.top;
  337.     aspect = get_aspect_ratio();
  338.     set_view(2.*aspect,2.,1.*aspect,1.);
  339.  
  340.     myWindow = gDrawWindow;
  341. }
  342.  
  343. /************************************************************************
  344. *    Return screen aspect ratio: width/height
  345. ************************************************************************/
  346. double    get_aspect_ratio(void)
  347. {
  348.     return (double) gDrawwidth/(double) gDrawheight;
  349. }
  350.  
  351. /************************************************************************
  352. *    Define view coordinate system for draw_line(), draw_circle(), etc.
  353. ************************************************************************/
  354. void    set_view(double width,double height,double x,double y)
  355. {
  356.     gViewwidth = width;
  357.     gViewheight = height;
  358.     gViewx = x;
  359.     gViewy = y;
  360. }
  361.  
  362. /************************************************************************
  363. *    Transform view coordinate x to screen coordinates
  364. ************************************************************************/
  365. static int    transform_x(double x)
  366. {
  367.     return (int) ((x+gViewx)*(double) gDrawwidth/gViewwidth);
  368. }
  369.  
  370. /************************************************************************
  371. *    Transform view coordinate y to screen coordinates
  372. ************************************************************************/
  373. static int    transform_y(double y)
  374. {
  375.     return (int) ((gViewheight-gViewy-y)*(double) gDrawheight/gViewheight);
  376. }
  377.  
  378. /************************************************************************
  379. *    draw_line() is used to draw lines using view coordinates.
  380. ************************************************************************/
  381. void        draw_line(double x1,double y1,double x2,double y2)
  382. {
  383.     int        screen_x1,
  384.             screen_y1,
  385.             screen_x2,
  386.             screen_y2;
  387.  
  388.     screen_x1 = transform_x(x1);
  389.     screen_y1 = transform_y(y1);
  390.     screen_x2 = transform_x(x2);
  391.     screen_y2 = transform_y(y2);
  392.     
  393.     MoveTo(screen_x1,screen_y1);
  394.     LineTo(screen_x2,screen_y2);
  395. }
  396.  
  397. /************************************************************************
  398. *    Move present pen position to new position using view
  399. *    coordinates.  Nothing is drawn.
  400. ************************************************************************/
  401. void    move_to(double x,double y)
  402. {
  403.     int        screen_x,
  404.             screen_y;
  405.             
  406.     screen_x = transform_x(x);
  407.     screen_y = transform_y(y);
  408.     
  409.     MoveTo(screen_x,screen_y);
  410.     return;
  411. }
  412.  
  413. /************************************************************************
  414. *    Draw from present pen position to new position using view
  415. *    coordinates.
  416. ************************************************************************/
  417. void    draw_to(double x,double y)
  418. {
  419.     int        screen_x,
  420.             screen_y;
  421.             
  422.     screen_x = transform_x(x);
  423.     screen_y = transform_y(y);
  424.     
  425.     LineTo(screen_x,screen_y);
  426.     return;
  427. }
  428.  
  429. /************************************************************************
  430. *    draw_circle() draws a circle using the Mac Toolbox routines.  It
  431. *    accepts view coordinates.
  432. ************************************************************************/
  433. void draw_circle(double x,double y,double r)
  434. {
  435.     Rect    myRect,
  436.             *myRectPtr;
  437.     int        screen_x,
  438.             screen_y,
  439.             screen_r;
  440.             
  441.     screen_x = transform_x(x);
  442.     screen_y = transform_y(y);
  443.     screen_r = (int) (r*(double) gDrawwidth/gViewwidth);
  444.     
  445.     myRectPtr = &myRect;
  446.     
  447.     myRectPtr->left = screen_x-screen_r;
  448.     myRectPtr->right = screen_x+screen_r;
  449.     myRectPtr->top = screen_y-screen_r;
  450.     myRectPtr->bottom = screen_y+screen_r;
  451.     
  452.     FrameOval(&myRect);
  453.     
  454.     circle_rect = myRect;
  455.     
  456.     return;         
  457. }
  458.  
  459. /************************************************************************
  460. *    fill_circle() draws a circle using the Mac Toolbox routines.  It
  461. *    accepts view coordinates.  The circle is filled with the present
  462. *    pen color
  463. ************************************************************************/
  464. void fill_circle(double x,double y,double r)
  465. {
  466.     Rect    myRect,
  467.             *myRectPtr;
  468.     int        screen_x,
  469.             screen_y,
  470.             screen_r;
  471.             
  472.     screen_x = transform_x(x);
  473.     screen_y = transform_y(y);
  474.     screen_r = (int) (r*(double) gDrawwidth/gViewwidth);
  475.     
  476.     myRectPtr = &myRect;
  477.     
  478.     myRectPtr->left = screen_x-screen_r;
  479.     myRectPtr->right = screen_x+screen_r;
  480.     myRectPtr->top = screen_y-screen_r;
  481.     myRectPtr->bottom = screen_y+screen_r;
  482.     
  483.     PaintOval(&myRect);
  484.  
  485.     circle_rect = myRect;
  486.     
  487.     return;         
  488. }
  489.  
  490. /************************************************************************
  491. *    mouse_button_is_down() checks whether the mouse button is down,
  492. *    returns 1 if so, 0 if not.
  493. ************************************************************************/
  494. int        mouse_button_is_down(void)
  495. {
  496.     return Button();
  497. }
  498.  
  499. /************************************************************************
  500. *    get_mouse_location returns the mouse coordinates in terms of the 
  501. *    view coordinate system.  It calls the appropriate Mac Toolbox
  502. *    function to get the Mac screen coordinates of the mouse, and uses
  503. *    the inverse transformation of that in transform_x() and transform_y().
  504. ************************************************************************/
  505. void    get_mouse_location(double *x_ptr,double *y_ptr)
  506. {
  507.     Point        mouseLoc;
  508.     
  509.     GetMouse(&mouseLoc);
  510.     *x_ptr = (double) mouseLoc.h/(double) gDrawwidth*gViewwidth-gViewx;
  511.     *y_ptr = gViewheight-gViewy-gViewheight*
  512.             (double) mouseLoc.v/(double) gDrawheight;
  513.  
  514.     return;
  515. }
  516.     
  517. /************************************************************************
  518. *    wait until button is pressed
  519. ************************************************************************/
  520. void    wait(void)
  521. {
  522.     while (!Button())
  523.         ;
  524. }
  525.  
  526. # ifdef SYNC
  527. /************************************************************************
  528. *    Task
  529. ************************************************************************/
  530. pascal void Task(void)
  531. {
  532.     long        oldA5;
  533.     MYVBLTASK    vbltask;
  534.     
  535.     asm
  536.     {
  537.         move.l    A5,oldA5    ; save off the old value of A5
  538.         move.l    -4(A0), A5    ; A0 points to our VBL task record and ear...
  539.                             ; save CurrentA5 near it
  540.     }
  541.     
  542.     vCounter++;
  543.     mytask.task.vblCount = 1;    // we want to run again real soon
  544.     
  545.     asm
  546.     {
  547.         move.l    oldA5,A5
  548.     }
  549. }
  550.  
  551. /************************************************************************
  552. *    InstallSync
  553. ************************************************************************/
  554. void    InstallSync(void)
  555. {
  556.     GetVideoDefault(&video);
  557.     
  558.     mytask.goodA5 = (long) CurrentA5;
  559.     vCounter = 0;
  560.     
  561.     mytask.task.qType = vType;
  562.     mytask.task.vblAddr = (ProcPtr) Task;
  563.     mytask.task.vblCount = 1;
  564.     mytask.task.vblPhase = 0;
  565.     SlotVInstall((QElemPtr) &mytask.task,video.sdSlot);
  566. }
  567.  
  568. /************************************************************************
  569. *    RemoveSync
  570. ************************************************************************/
  571. void    RemoveSync(void)
  572. {
  573.     SlotVRemove((QElemPtr) &mytask.task,video.sdSlot);
  574. }
  575.  
  576. /************************************************************************
  577. *    WaitForSync
  578. ************************************************************************/
  579. void    WaitForSync(void)
  580. {
  581.     long    vJunk = vCounter;
  582.     
  583.     do {} while (vCounter==vJunk);
  584. }
  585. # endif
  586.  
  587.  
  588.  
  589.     
  590.